/*
 * Copyright 2009 Michal Trzcinka
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

YAHOO.namespace('TRZCINKA.VCARD');
YAHOO.namespace('TRZCINKA.VCARD.MODEL');

(function() {

  var CustomEvent = YAHOO.util.CustomEvent,
      Lang = YAHOO.lang,
      Constants = YAHOO.TRZCINKA.VCARD.Constants,
      LOGGER = new YAHOO.widget.LogWriter('model.js'),
      JSON = YAHOO.lang.JSON,
      Config = YAHOO.TRZCINKA.VCARD.Config;

  YAHOO.TRZCINKA.VCARD.MODEL.byLocation = function(location) {
    return function(item) {
      return item.location.equals(location);
    };
  };

  YAHOO.TRZCINKA.VCARD.MODEL.byOrder = function(a, b) {
    return a.order - b.order;
  };

  var byLocation = YAHOO.TRZCINKA.VCARD.MODEL.byLocation;
  var byOrder = YAHOO.TRZCINKA.VCARD.MODEL.byOrder;

  YAHOO.TRZCINKA.VCARD.GridModel = function() {
    LOGGER.log('instantiating GridModel', 'debug');
    var gridData = null;

    this.gridModelEvent = new CustomEvent(Constants.VCARD_EVENT, this);

    this.getTopItem = function(location) {
      LOGGER.log('getting top item at location ' + location.toJSON(), 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to get top item while grid model not initialized yet!', 'error');
        return;
      }

      return gridData.items.findAll(byLocation(location)).max(byOrder);
    };

    this.loadGrid = function(gridDataParam) {
      LOGGER.log('GridModel.loadGrid called with ' + gridDataParam, 'debug');
      gridData = gridDataParam;
      this.gridModelEvent.fire([Constants.MODEL_LOADED_EVENT, gridData]);
    };

    this.getGridData = function() {
      return gridData;
    };

    this.getGridId = function() {
      return gridData.id;
    };

    this.itemExists = function(location) {
      LOGGER.log('checking if item ' + JSON.stringify(location) + ' exists', 'debug');
      if (gridData.items == undefined) {
        return false;
      }
      for (var i = 0; i < gridData.items.length; i++) {
        var item = gridData.items[i];
        if (item.location.equals(location)) {
          return true;
        }
      }
      return false;
    };

    this.createItem = function(location) {
      LOGGER.log('creating item at ' + JSON.stringify(location), 'debug');
      var item = {location: location, text: '', backgroundColor: Config.DEFAULT_BACKGROUND_COLOR, foregroundColor: Config.DEFAULT_FOREGROUND_COLOR, order: 1};
      if (gridData.items == undefined) {
        gridData.items = [item];
      } else {
        gridData.items.push(item);
      }

      this.gridModelEvent.fire([Constants.ITEM_CREATED_EVENT, item]);
    };

    this.setText = function(location, text) {
      LOGGER.log('setting text at ' + JSON.stringify(location) + ' with ' + text, 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to update item while grid model not initialized yet!', 'error');
        return;
      }

      var item = this.getTopItem(location);
      if (item) {
        item.text = text;
      } else {
        LOGGER.log('could not update item ' + JSON.stringify(location) + ' because it does not exist', 'warn');
      }
    };

    this.setBackgroundColor = function(location, color) {
      LOGGER.log('setting background color at ' + JSON.stringify(location) + ' with ' + color, 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to update item while grid model not initialized yet!', 'error');
        return;
      }

      var item = this.getTopItem(location);
      if (item) {
        item.backgroundColor = color;
        this.gridModelEvent.fire([Constants.BACKGROUND_COLOR_SET_EVENT, {
          location: location,
          color: color
        }]);
      } else {
        LOGGER.log('could not update item ' + JSON.stringify(location) + ' because it does not exist', 'warn');
      }
    };

    this.setForegroundColor = function(location, color) {
      LOGGER.log('setting foreground color at ' + JSON.stringify(location) + ' with ' + color, 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to update item while grid model not initialized yet!', 'error');
        return;
      }

      var item = this.getTopItem(location);
      if (item) {
        item.foregroundColor = color;
        this.gridModelEvent.fire([Constants.FOREGROUND_COLOR_SET_EVENT, {
          location: location,
          color: color
        }]);
      } else {
        LOGGER.log('could not update item ' + JSON.stringify(location) + ' because it does not exist', 'warn');
      }
    };

    this.moveItem = function(oldLocation, newLocation) {
      LOGGER.log('moving item from ' + JSON.stringify(oldLocation) + ' to ' + JSON.stringify(newLocation), 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to move item while grid model not initialized yet!', 'error');
        return;
      }

      var oldItem = this.getTopItem(oldLocation);
      if (!oldItem) {
        LOGGER.log('trying to move not existing item!', 'error');
        return;
      }
      var newLocationTopItem = this.getTopItem(newLocation);
      if (newLocationTopItem) {
        oldItem.order = newLocationTopItem.order + 1;
      }
      oldItem.location = newLocation;
      this.gridModelEvent.fire([Constants.ITEM_MOVED_EVENT, {
        oldLocation: oldLocation,
        newLocation: newLocation,
        order: oldItem.order
      }]);

    };

    this.moveStack = function(oldLocation, newLocation) {
      LOGGER.log('moving stack from ' + JSON.stringify(oldLocation) + ' to ' + JSON.stringify(newLocation), 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to move items while grid model not initialized yet!', 'error');
        return;
      }

      var stack = this.getItems(oldLocation);

      if (this.itemExists(newLocation)) {
        stack.sort(byOrder);
        var topOrder = this.getTopItem(newLocation).order;
        stack.each(function (item) {
          item.location = newLocation;
          item.order = topOrder++;
        });
      } else {
        stack.each(function (item) {
          item.location = newLocation;
        });
      }

      this.gridModelEvent.fire([Constants.STACK_MOVED_EVENT, {
        oldLocation: oldLocation,
        newLocation: newLocation
      }]);


    };

    this.removeItem = function(location) {
      LOGGER.log('removing item at ' + JSON.stringify(location), 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to remove item while grid model not initialized yet!', 'error');
        return;
      }

      var item = this.getTopItem(location);
      var removed = gridData.items.remove(item);
      if (removed) {
        this.gridModelEvent.fire([Constants.ITEM_REMOVED_EVENT, location]);
      } else {
        LOGGER.log('trying to remove not existing item!', 'error');
      }
    };

    this.getItems = function(location) {
      LOGGER.log('getting items at ' + JSON.stringify(location), 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to get item while grid model not initialized yet!', 'error');
        return;
      }

      return gridData.items.findAll(byLocation(location));
    };

    this.setTopItem = function(location, order) {
      LOGGER.log('setting top item at ' + JSON.stringify(location), 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to set top item while grid model not initialized yet!', 'error');
        return;
      }

      var stack = gridData.items.findAll(byLocation(location)).sort(byOrder);
      var removed = stack.remove(function(item) {
        return item.order == order;
      })[0];
      stack.push(removed);

      for (var i = 0; i < stack.length; i++) {
        stack[i].order = i + 1;
      }

      this.gridModelEvent.fire([Constants.TOP_ITEM_SET_EVENT, {
        location: location,
        item: removed
      }]);
    };

    this.isStack = function(location) {
      LOGGER.log('checking if location is stack at ' + JSON.stringify(location), 'debug');
      if (gridData.items == undefined) {
        LOGGER.log('trying to check while grid model not initialized yet!', 'error');
        return;
      }

      return gridData.items.findAll(byLocation(location)).length > 1;
    };

  };

}());